import random
import pickle
from flask import Flask,render_template,redirect,url_for, \
                    request,session,g

import threading
from threading import Thread

import os
import re

from queue import PriorityQueue


from config import *
from dbthing import *


pattern = re.compile(r"(.*?)\.txt")


def get_user(username:str):
    item = collection_user.find_one({'_id':username})
    user = User(username, item['password'],
                item['history'], item['history_reward'],
                item['hobby'],
                item['friend_preference'],item['transition_preference'])
    return user


def into_db(user:User):
    collection_user.update({'_id':user.username},
                           {'_id':user.username,
                            'password':user.password,
                            'history':user.history,
                            'history_reward':user.history_reward,
                            'hobby':user.hobby.tolist(),
                            'friend_preference':user.friend_preference.tolist(),
                            'transition_preference':user.transition_preference.tolist()})


# 默认Flask的构造方法中,
# static_folder='static', 后端拿东西的路径, 所以要在根目录下面加static文件夹
# template_folder='template', 后端拿东西的路径, 所以要在根目录下面加template文件夹, 放html文件
# app.py以自己所在的目录为根目录
# 其他都是None
app = Flask(__name__)
# app = Flask(__name__, root_path = os.getcwd())
# 可以设置app.py所在的文件夹为根目录

# app = Flask(__name__, static_url_path = '', root_path = os.getcwd())
# 把static_url_path设为空


app.secret_key = b'qwe123'   # 这里设置secret_key


# 到了主页
# 只有点"刷新"才把当前计算结果发给用户
@app.route('/', methods=['GET'])
@app.route('/index', methods=['GET'])
def index():
    n_user = len(collection_user.find())

    # 已登录
    if 'username' in session:
        username = session['username']
        res = db_redis.lpop(username)
        if res == None:
            recommend_user = list(collection_user.find())
        else:
            recommend_user = pickle.loads(res)

    # 未登录
    else:
        username = ''
        if n_user <= n_recommend:
            recommend_user = list(collection_user.find())
        else:
            recommend_user = list(collection_user.find())
            recommend_user = random.sample(recommend_user, n_recommend)


    return render_template('index.html', all_hobby=all_hobby, friends=recommend_user, username=username)  # 注意传变量给模板要这样写


# 如果用户点击退出登陆, 就到这里
@app.route('/logout', methods=['GET'])
def logout():
    session.pop('username', None)
    return redirect(url_for('index'))




# 上传文件
@app.route('/upload', methods=['GET', 'POST'])
def upload():
    if request.method == 'GET':
        print(os.getcwd())
        return render_template('upload.html')  # 这里是上传文件的前端
    else:
        f = request.files['file']
        f.save(os.getcwd() + "/a.txt")
        return redirect(url_for('upload'))


# 注册页面
@app.route('/signup', methods=['GET', 'POST'])
def signup():
    return render_template('signup.html')


# 计算备选用户集合里面可能的组合
# 这可能是个漫长的过程, 当消息队列里面有请求更新的消息时, 就停止
def cal(user:User, potential_users:list):

    best_seqs = PriorityQueue(n_recommend)

    while(True):
        # 生成一个序列
        while(True):
            seq = random.sample(potential_users, potential_users)
            if seq[0] != user.username:
                break

        reward_all = 0
        former_friend = user.history[-1]

        for i in seq:
            reward_all += user.friend_gain(i['hobby'])
            reward_all += user.transition_gain(former_friend, i['hobby'])

            if not best_seqs.full():  # 如果没有满, 直接放进去
                best_seqs.put(RewardUser(reward_all, user.username))

            else:  # 如果满了, 把最小的拿出来, 跟新的reward比较
                min_reward = best_seqs.queue[0]  # 获取优先队列中最小的reward
                if reward_all > min_reward:
                    best_seqs.get()
                    best_seqs.put(RewardUser(reward_all, user.username))

        # 检查消息队列里面是不是有消息, 如果有, 就停了
        msg = db_redis.lpop(user.name)
        if msg != None:
            break

    # 把获取的推荐用户放进去
    db_redis.lpush(user.username, pickle.dumps(list(best_seqs.queue)))




## 点击注册按钮之后到这里
@app.route('/dealsignup', methods=['POST'])
def dealsignup():
    if 'username' not in request.form or request.form['username'] == '':
        return render_template('slerr.html')  # 没输入用户名
    elif 'password' not in request.form or request.form['password'] == '':
        return render_template('slerr.html')  # 没输入密码

    global all_hobby

    hobby_vec = [0 for i in range(n_feature)]
    friend_preference = [0.2 for i in range(n_feature)]
    transition_preference = np.random.random((14,2,2)).tolist()

    print(transition_preference)

    for idx,hobby in enumerate(all_hobby):
        if hobby in request.form:
            hobby_vec[idx] = 1
            friend_preference[idx] = 0.8

    try:
        # 插入一条用户
        collection_user.insert({'_id':request.form['username'],
                                'password':request.form['password'],
                                'history':[hobby],
                                'history_reward':[0.5],
                                'hobby':hobby_vec,
                                'friend_preference':friend_preference,
                                'transition_preference':transition_preference})

        # 用户数+1
        # n_user = collenction_statistic.find_one()['n_user']
        # collenction_statistic.update({'n_user':{"$gte":0}},
        #                              {'n_user':n_user+1})

    except:
        return render_template('duplicate.html')  # 内容是用户名重复了

    # 初始化用户
    user = get_user(request.form['username'])

    # 给这个用户开一个线程?
    potential_user = collection_user.find()
    new_thread = Thread(target=cal, args=(user, potential_user))
    new_thread.start()

    session['username'] = request.form['username']  # 注册完, 保持登陆

    return redirect(url_for('index'))


# 登陆页面
@app.route('/login', methods=['GET', 'POST'])
def login():
    return render_template('login.html')


## 点击完登陆按钮就进入这里
@app.route('/deallogin', methods=['POST'])
def dealloginin():
    if 'username' not in request.form:
        return render_template('slerr.html')  # 没输入用户名
    elif 'password' not in request.form:
        return render_template('slerr.html')  # 没输入密码

    res = collection_user.find_one({'_id':request.form['username'],'password':request.form['password']})

    if res is not None:
        session['username'] = request.form['username']  # 保持登陆
        return redirect(url_for('index'))
    else:
        return render_template('lerr.html')  # 用户名或者密码错误

# 处理反馈信息
@app.route('/response', methods=['POST'])
def response():
    # session['username']
    db_redis.lpush(session['username'],1)  # 让计算线程结束了, 然后计算线程会把结果放进"username_current"的队列里
    recommend_list = pickle.loads(db_redis.get(session['username']))  # 从消息队列中拿数据


    # 更新模型
    if 'good' in request.form:
        reward = 0.7
    elif 'normal' in request.form:
        reward = 0.5
    else:
        reward = 0.3

    user = get_user(session['username'])
    friend = collection_user.find(recommend_list[0].username)['hobby']
    user.update(friend, reward)

    # 更新完之后写入数据库
    into_db(user)

    # 开启线程
    potential_user = collection_user.find()
    new_thread = Thread(target=cal, args=(user, potential_user))
    new_thread.start()

    return redirect(url_for('index'))


if __name__ == '__main__':

    # collenction_statistic.update({'n_user':{'$gte':0}}, {'n_user':0})

    # db_redis.sadd('thing','init','init')
    # g.nothing = 'nothing'
    app.run()

    # print(collection_user.find())


    # app.run(host="0.0.0.0")
    # 默认地址是127.0.0.1, 可以设置
    # 默认端口是5000, 可以设置
    # app.run(host='0.0.0.0',port=5050)  #0.0.0.0和127.0.0.1好像是一样的


    # i = np.random.randint(0,2,(n_feature))   # 自己的爱好
    #
    # j = np.random.random((n_feature))   # 对朋友的偏好
    #
    # k = np.random.random((n_feature,2,2))   # 对转换的偏好
    #
    #
    # a = User('a','a',history=[i], history_reward=[0.6], hobby=i, friend_preference=j, transition_preferece=k)
    #
    # friend = np.random.randint(0,2,(n_feature))
    #
    #
    # print(a.friend_gain(friend))
    #
    #
    # a.update(friend,0.4)
    #
    #
    # print(a.friend_gain(friend))









